package com.bumptech.glide;

import android.support.annotation.NonNull;

import com.bumptech.glide.request.transition.NoTransition;
import com.bumptech.glide.request.transition.TransitionFactory;
import com.bumptech.glide.request.transition.ViewAnimationFactory;
import com.bumptech.glide.request.transition.ViewPropertyAnimationFactory;
import com.bumptech.glide.request.transition.ViewPropertyTransition;
import com.bumptech.glide.util.Preconditions;

/**
 * A base class for setting a transition to use on a resource when a load completes.
 * <p>
 * 过渡动画设定类
 *
 * @param <CHILD>         The implementation of this class to return to chain methods.
 * @param <TranscodeType> The type of resource that will be animated.
 */
public abstract class TransitionOptions<CHILD extends TransitionOptions<CHILD, TranscodeType>,
        TranscodeType> implements Cloneable {
    private TransitionFactory<? super TranscodeType> transitionFactory = NoTransition.getFactory();

    /**
     * Removes any existing animation put on the builder. Will be overridden by subsequent calls that
     * put an animation.
     *
     * @return This request builder.
     */
    @NonNull
    public final CHILD dontTransition() {
        return transition(NoTransition.getFactory());
    }

    /**
     * Sets an {@link android.view.animation.Animation} to run on the wrapped target when an resource
     * load finishes.
     * Will only be run if the resource was loaded asynchronously (i.e. was not in the memory cache).
     *
     * @param viewAnimationId The resource id of the {@link android.view.animation} to use as the
     *                        transition.
     * @return This request builder.
     */
    @NonNull
    public final CHILD transition(int viewAnimationId) {
        return transition(new ViewAnimationFactory<>(viewAnimationId));
    }

    /**
     * Sets an animator to run a {@link android.view.ViewPropertyAnimator} on a view that the target
     * may be wrapping when a resource load finishes.
     * Will only be run if the load was loaded asynchronously (i.e. was not in the memory cache).
     *
     * @param animator The {@link ViewPropertyTransition
     *                 .Animator} to run.
     * @return This request builder.
     */
    @NonNull
    public final CHILD transition(@NonNull ViewPropertyTransition.Animator animator) {
        return transition(new ViewPropertyAnimationFactory<>(animator));
    }

    /**
     * Uses the given {@link TransitionFactory} to build a
     * {@link com.bumptech.glide.request.transition.Transition} for each request started with these
     * {@code TransitionOptions}.
     *
     * @return This request builder.
     */
    @NonNull
    public final CHILD transition(
            @NonNull TransitionFactory<? super TranscodeType> transitionFactory) {
        this.transitionFactory = Preconditions.checkNotNull(transitionFactory);
        return self();
    }

    @SuppressWarnings({
            // cast to CHILD is safe given the generic argument represents the object's runtime class
            "unchecked",
            // CHILD is the correct class name.
            "PMD.CloneMethodReturnTypeMustMatchClassName",
            // we don't want to throw to be user friendly
            "PMD.CloneThrowsCloneNotSupportedException"
    })
    @Override
    public final CHILD clone() {
        try {
            return (CHILD) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    final TransitionFactory<? super TranscodeType> getTransitionFactory() {
        return transitionFactory;
    }

    @SuppressWarnings("unchecked")
    private CHILD self() {
        return (CHILD) this;
    }
}
